package gao.xiaolei.service;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import gao.xiaolei.dao.*;
import gao.xiaolei.dto.UserBaseDetail;
import gao.xiaolei.entity.*;
import gao.xiaolei.exception.AuthException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import gao.xiaolei.dto.UserOutDto;
import gao.xiaolei.util.GsonUtil;
import gao.xiaolei.util.RedisUtil;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service("UserService")
public class UserService {

    @Resource(name = "UserDao")
    private UserDao userDao;

    @Resource(name = "RoleDao")
    private RoleDao roleDao;

    @Resource(name = "UserRoleDao")
    private UserRoleDao userRoleDao;

    @Resource(name = "GroupDao")
    private GroupDao groupDao;

    @Resource(name = "ClassesDao")
    private ClassesDao classesDao;

    @Resource(name = "UserClassesDao")
    private UserClassesDao userClassesDao;

    @Resource(name = "GroupMemberDao")
    private GroupMemberDao groupMemberDao;

    @Resource(name = "GroupManageDao")
    private GroupManageDao groupManageDao;

    @Resource(name = "AuthVersionDao")
    private AuthVersionDao authVersionDao;

    @Resource(name = "GsonUtil")
    private GsonUtil gsonUtil;

    @Resource(name = "RedisUtil")
    private RedisUtil redis;

    @Resource(name = "PasswordEncoder")
    private PasswordEncoder passwordEncoder;

    @Transactional
    public Integer addUserForAdmin(String newUserJson) {
        JsonObject userObject = new JsonParser().parse(newUserJson)
                .getAsJsonObject();
        String id = userObject.get("id").getAsString();
        String userName = userObject.get("userName").getAsString();
        String realName = userObject.get("realName").getAsString();
        String password = userObject.get("password").getAsString();
        JsonArray rolesArray = userObject.get("roleIds").getAsJsonArray();
        User u = new User();
        if (userDao.getUserNameCount(userName) > 0)
            return 0;
        u.setUsername(userName);
        u.setPassword(passwordEncoder.encode(password));
        u.setRealName(realName);
        for (JsonElement role : rolesArray) {
            userRoleDao.save(new UserRole(id, role.getAsString()));//保存用户角色信息
        }
        u.setId(id);
        userDao.save(u);
        return 1;
    }

    @Transactional
    public Integer updateUser(String newUserJson) {
        JsonObject userObject = new JsonParser().parse(newUserJson)
                .getAsJsonObject();
        String id = userObject.get("id").getAsString();
        String userName = userObject.get("userName").getAsString();
        String realName = userObject.get("realName").getAsString();
        String password = userObject.get("password").getAsString();
        JsonArray rolesArray = userObject.get("roleIds").getAsJsonArray();
        User u = userDao.findById(id).get();
        List<String> oldRoles = userRoleDao.getRoleByUserId(id);//获取之前的角色信息
        if (!u.getUsername().equals(userName)) {//如果修改了用户名
            if (userDao.findByUsername(userName) != null)//如果用户名已经存在
                return 0;
            userDao.updateUserName(userName, id);
        }
        if (!("".equals(password) || passwordEncoder.matches(password,
                u.getPassword())))//如果密码更改了才去更改密码
            userDao.updatePassword(id, passwordEncoder.encode(password));
        if (!u.getRealName().equals(realName))//如果真实姓名更改了的话才去更改
            userDao.updateRealName(realName, id);
        int flag = 0;
        // 用于判断用户修改的新角色和旧角色之间是否有差别
        for (int i = 0, length = oldRoles.size(); i < length; i++) {
            for (JsonElement newRole : rolesArray) {
                if (oldRoles.get(i).equals(newRole.getAsString())) {
                    flag = 1;// flag值为1代表没有比较出差别（即旧的有，新的也有）
                    break;
                }
                flag = 0;// 说明此次循环没找到一样的
            }
        }
        if (flag == 1) {// 第一次比较比不出差别才进入第二次交换比较
            for (JsonElement newRole : rolesArray) {
                for (int i = 0, length = oldRoles.size(); i < length; i++) {
                    if (oldRoles.get(i).equals(newRole.getAsString())) {
                        flag = 1;// flag值为1代表没有比较出差别（即新的有，旧的也有）
                        break;
                    }
                    flag = 0;// 说明此次循环没找到一样的
                }
            }
        }
        // 新旧角色之间有差别才去修改数据库
        if (flag == 0) {
            userRoleDao.deleteAllByUserId(id);//先删除全部的角色信息
            for (JsonElement newRole : rolesArray) {
                userRoleDao.save(new UserRole(id, newRole.getAsString()));//然后在添加新的角色信息
            }
            userDao.save(u);
            //更改了角色说明权限要发生改变，所以要将权限版本号变更
            refreshUserAuthVersionCache(u.getId());
        }
        return 1;
    }

    @Transactional
    //更新某个人的角色信息
    public void updateUserRole(String userId, List<String> newRoles) {
        userRoleDao.deleteAllByUserId(userId);
        userRoleDao.save(new UserRole(userId, roleDao.getIdByName("ROLE_BASE")));//基础角色不能删
        for (int i = 0, length = newRoles.size(); i < length; i++) {
            userRoleDao.save(new UserRole(userId, roleDao.getIdByName(newRoles.get(i))));//然后在添加新的角色信息
        }
        //更改了角色说明权限要发生改变，所以要将权限版本号变更
        refreshUserAuthVersionCache(userId);
    }

    @Transactional
    public void deleteUser(String idJson) {
        JsonArray ids = new JsonParser().parse(idJson).getAsJsonArray();
        User u = new User();
        for (JsonElement id : ids) {
            u.setId(id.getAsJsonObject().get("id").getAsString());
            userDao.delete(u);
            userRoleDao.deleteAllByUserId(id.getAsJsonObject().get("id").getAsString());
        }
    }

    public List<Role> getRoles(String userId) {
        return roleDao.findAllById(userRoleDao.getRoleByUserId(userId));
    }

    public List<User> getAll() {
        return userDao.findAll();
    }

    public String getRealName(String id) {
        return userDao.getRealName(id);
    }

    public List<Groupcs> getInWitchGroupIsLeader(String id) {
        List<String> gIds = groupMemberDao.queryGroupByLeader(id);
        return groupDao.findAllById(gIds);
    }

    public String getGroupName(String groupId) {
        return groupDao.getGroupName(groupId);
    }

    public String getGroupLeader(String groupId) {
        return groupMemberDao.queryGroupLeader(groupId);
    }

    public String getGroupLeadingCadre(String groupId) {
        return groupManageDao.getGroupLeadingCadre(groupId);
    }

    public List<String> getGroupMembers(String groupId) {
        return groupMemberDao.queryGroupMember(groupId);
    }

    @Transactional(readOnly = true)
    //获取所有老师列表,用于挑选班级的负责人
    public List<UserOutDto> getDirectorList() {
        String roleId = roleDao.getIdByName("ROLE_DIRECTOR");
        List<String> userIds = userRoleDao.getUserByRoleId(roleId);
        List<User> directors = userDao.findAllById(userIds);
        List<UserOutDto> dtos = new ArrayList<>(directors.size());
        for (int i = 0, length = directors.size(); i < length; i++) {
            dtos.add(new UserOutDto(directors.get(i).getId(), directors.get(i).getRealName(), directors.get(i).getUsername(), classesDao.countAllByCreater(directors.get(i).getId())));
        }
        return dtos;
    }

    @Transactional(readOnly = true)
    //获取所有老师列表,用于挑选班级的负责人
    public List<UserOutDto> getTeacherList() {
        String roleId = roleDao.getIdByName("ROLE_TEACHER");
        List<String> userIds = userRoleDao.getUserByRoleId(roleId);
        List<User> teachers = userDao.findAllById(userIds);
        List<UserOutDto> dtos = new ArrayList<>(teachers.size());
        for (int i = 0, length = teachers.size(); i < length; i++) {
            dtos.add(new UserOutDto(teachers.get(i).getId(), teachers.get(i).getRealName(), teachers.get(i).getUsername(), classesDao.countAllByLeader(teachers.get(i).getId())));
        }
        return dtos;
    }

    @Transactional(readOnly = true)
    //获取所有的普通用户列表,用于挑选班级的成员
    public List<UserOutDto> getStudentListList() {
        List<String> roleNames = new ArrayList<>(2);
        roleNames.add("ROLE_USER");
        roleNames.add("ROLE_GROUP_LEADER");
        List<String> roleIds = roleDao.getAllIdByNameIn(roleNames);
        List<String> userIds = userRoleDao.getUserByRoleIdIn(roleIds).stream().distinct().collect(Collectors.toList());//查出来的用户可能重复，要去重
        List<User> students = userDao.findAllById(userIds);
        List<UserOutDto> dtos = new ArrayList<>(students.size());
        for (int i = 0, length = students.size(); i < length; i++) {
            dtos.add(new UserOutDto(students.get(i).getId(), students.get(i).getRealName(), students.get(i).getUsername(), userClassesDao.countAllByUserId(students.get(i).getId())));
        }
        return dtos;
    }

    //获取用户基本信息（用户名、昵称）
    @Transactional(readOnly = true)
    public UserBaseDetail getUserBaseDetail(String userId) {
        User user = userDao.findById(userId).orElseThrow(() -> new IllegalArgumentException("该用户("
                .concat(userId)
                .concat(")不存在！")));
        List<String> roleIds = userRoleDao.getRoleByUserId(userId);
        List<String> roleNames = new ArrayList<>(roleIds.size());
        for (int i = 0, length = roleIds.size(); i < length; i++) {
            roleNames.add(roleDao.getChineseName(roleIds.get(i)));
        }
        return new UserBaseDetail(user, roleNames);
    }

    //更改用户基本信息（用户名、昵称）
    @Transactional
    public void updateUserBaseDetail(User inputUser) {
        User user = userDao.findById(inputUser.getId()).orElseThrow(() -> new IllegalArgumentException("该用户("
                .concat(inputUser.getId())
                .concat(")不存在！")));
        if (userDao.getUserNameCount(inputUser.getUsername()) > 0)
            throw new AuthException("该用户名已经存在！");
        user.setRealName(inputUser.getRealName());
        user.setUsername(inputUser.getUsername());
        userDao.save(user);
    }

    //用户修改密码
    @Transactional
    public void updatePassword(String userId, String oldPassword, String newPassword) {
        User user = userDao.findById(userId).orElseThrow(() -> new IllegalArgumentException("该用户("
                .concat(userId)
                .concat(")不存在！")));
        if (!passwordEncoder.matches(oldPassword, user.getPassword()))
            throw new AuthException("原密码不正确！");
        else
            userDao.updatePassword(userId, passwordEncoder.encode(newPassword));
    }

    //获取所有用户列表
    public List<User> getAllUser() {
        return userDao.findAll();
    }


    //刷新某人的权限版本号
    private void refreshUserAuthVersionCache(String userId) {
        AuthVersion av = authVersionDao.findById(userId).orElse(new AuthVersion(userId, 0));
        av.setVersion(av.getVersion() + 1);
        authVersionDao.save(av);
        redis.set(userId, av.getVersion(), redis.EXPIRETIME);
    }

}
